package com.yueshop.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yueshop.common.mq.SeckillOrderTo;
import com.yueshop.common.to.OrderTo;
import com.yueshop.common.to.SkuHasStockVo;
import com.yueshop.common.utils.R;
import com.yueshop.common.vo.MemberRespVo;
import com.yueshop.order.constant.OrderConstant;
import com.yueshop.order.entity.OrderItemEntity;
import com.yueshop.order.entity.PaymentInfoEntity;
import com.yueshop.order.enume.OrderStatusEnum;
import com.yueshop.order.exception.NoStockException;
import com.yueshop.order.feign.CartFeignService;
import com.yueshop.order.feign.MemberrFeignService;
import com.yueshop.order.feign.ProductFeignService;
import com.yueshop.order.feign.WareFeignService;
import com.yueshop.order.interceptor.LoingUserInterceptor;
import com.yueshop.order.service.OrderItemService;
import com.yueshop.order.service.PaymentInfoService;
import com.yueshop.order.vo.*;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yueshop.common.utils.PageUtils;
import com.yueshop.common.utils.Query;

import com.yueshop.order.dao.OrderDao;
import com.yueshop.order.entity.OrderEntity;
import com.yueshop.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    private ThreadLocal<OrderSubmitVo> orderSubmitVoThreadLocal=new ThreadLocal<>();

    @Autowired
    MemberrFeignService memberrFeignService;
    @Autowired
    CartFeignService cartFeignService;
    @Autowired
    ThreadPoolExecutor executor;
    @Autowired
    WareFeignService wareFeignService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    ProductFeignService productFeignService;
    @Autowired
    OrderItemService orderItemService;

    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    PaymentInfoService paymentInfoService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo orderConfirm() throws ExecutionException, InterruptedException {
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        MemberRespVo memberRespVo = LoingUserInterceptor.loingUser.get();
        System.out.println("主线程.."+Thread.currentThread().getId());
        //获取老请求的 共享数据
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
            System.out.println("address.."+Thread.currentThread().getId());
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //1.获取用户收货地址列表
            List<MemberAddressVo> memberAddress = memberrFeignService.getMemberAddress(memberRespVo.getId());
            orderConfirmVo.setAddress(memberAddress);
        }, executor);

        CompletableFuture<Void> cartItemFuture = CompletableFuture.runAsync(() -> {
            //将主线程的请求头数据带到异步执行线程中进行共享, 解决异步调用丢失请求头的问题
            RequestContextHolder.setRequestAttributes(requestAttributes);
            System.out.println("cartItem.."+Thread.currentThread().getId());
            //2.获取购物车中被选中的购物项
            List<OrderItemVo> checkedItem = cartFeignService.getCheckedItem();
            //feign远程调用 使用很多的拦截器进行增强
            orderConfirmVo.setItems(checkedItem);
        }, executor).thenRunAsync(()->{
            //获取被选中的购物项 skuId 调用远程库存服务查询 该商品是否有库存
            List<OrderItemVo> items = orderConfirmVo.getItems();

            List<Long> skuids = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
            R r = wareFeignService.getSkusHasStock(skuids);
            List<SkuHasStockVo> list = r.getData(new TypeReference<List<SkuHasStockVo>>() {
            });
            if(list!=null){
                Map<Long, Boolean> map = list.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
                orderConfirmVo.setStocks(map);
            }
        },executor);

        //3.积分信息
        orderConfirmVo.setIntegration(memberRespVo.getIntegration());
        //4. 创建防止订单重复提交的 防重令牌 
        String token = UUID.randomUUID().toString().replace("-", "");
        stringRedisTemplate.opsForValue().set(OrderConstant.MEMBER_ORDER_TOKEN_PREFIX+memberRespVo.getId(),
                token,
                30, TimeUnit.MINUTES
                );
        orderConfirmVo.setOrderToken(token);
        CompletableFuture.allOf(addressFuture,cartItemFuture).get();
        return orderConfirmVo;
    }
    //@GlobalTransactional
    @Transactional
    @Override
    public OrderSubmitResponseVo submitOrder(OrderSubmitVo orderSubmitVo) {
        OrderSubmitResponseVo orderSubmitResponseVo = new OrderSubmitResponseVo();
        MemberRespVo memberRespVo = LoingUserInterceptor.loingUser.get();
        orderSubmitVoThreadLocal.set(orderSubmitVo);
        orderSubmitResponseVo.setCode(0);
        String orderToken = orderSubmitVo.getOrderToken();
        String script ="if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long code = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(OrderConstant.MEMBER_ORDER_TOKEN_PREFIX + memberRespVo.getId()), orderToken);
        if(code==0L){
            orderSubmitResponseVo.setCode(1);// 令牌验证失败
            return orderSubmitResponseVo;
        }else{
            //令牌验证成功了
            //下单操作:
            OrderCreateTo order = createOrder();
            //重新计算的应付价格
            BigDecimal payAmount = order.getOrder().getPayAmount();
            //页面提交的应付价格
            BigDecimal payPrice = orderSubmitVo.getPayPrice();
            if(Math.abs(payAmount.subtract(payPrice).doubleValue())<0.01){
                //验价通过保存订单及订单项
                saveOrder(order);
                //锁定库存
                //订单号 订单项信息 skuid num
                WareSkuLockVo wareSkuLockVo = new WareSkuLockVo();
                wareSkuLockVo.setOrderSn(order.getOrder().getOrderSn());
                List<OrderItemVo> orderItemVos = order.getOrderItems().stream().map(orderItemEntity -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(orderItemEntity.getSkuId());
                    orderItemVo.setCount(orderItemEntity.getSkuQuantity());
                    orderItemVo.setTitle(orderItemEntity.getSkuName());
                    return orderItemVo;
                }).collect(Collectors.toList());
                wareSkuLockVo.setLocks(orderItemVos);
                R r = wareFeignService.orderLockStock(wareSkuLockVo);
                if(r.getCode()==0){
                    //锁库存成功了
                    orderSubmitResponseVo.setOrder(order.getOrder());

                    //发送订单创建成功消息
                    rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getOrder());
                    //TODO 远程扣减积分
                   // int i=1/0;
                    return orderSubmitResponseVo;
                }else {
                    //说明锁定失败了
                    throw new NoStockException((String)r.get("msg"));
                }

            }else{
                //金额对比失败
                orderSubmitResponseVo.setCode(2);
                return orderSubmitResponseVo;
            }

        }
    }

    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        return baseMapper.selectOne(new QueryWrapper<OrderEntity>().eq("order_sn",orderSn));
    }

    @Override
    public void closeOrder(OrderEntity orderEntity) {
        //关闭订单之前查询当前订单状态.
        OrderEntity entity = baseMapper.selectById(orderEntity.getId());
        if(entity.getStatus()==OrderStatusEnum.CREATE_NEW.getCode()){
            //状态为0  表示待付款 进行超时自动关单.
            OrderEntity entity1 = new OrderEntity();
            entity1.setId(orderEntity.getId());
            entity1.setStatus(OrderStatusEnum.CANCLED.getCode());
            baseMapper.updateById(entity1);

            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderEntity,orderTo);
            //使用mq发送消息 通知锁库存服务解锁库存.
            try {
                rabbitTemplate.convertAndSend("order-event-exchange","order.release.other",orderTo);
            } catch (AmqpException e) {
                e.printStackTrace();
                //TODO 将没有发送成功的消息进行重新发送,
            }
        }
    }
    //获取商品支付需要的信息
    @Override
    public PayVo payOrder(String orderSn) {
        PayVo payVo = new PayVo();
        OrderEntity orderEntity = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        BigDecimal bigDecimal = orderEntity.getPayAmount().setScale(2, BigDecimal.ROUND_UP);
        //获取总金额. 数据库中付款金额有4位 但是支付宝只能接收2位所以向上取整两位数
        payVo.setTotal_amount(bigDecimal.toString());

        //订单号
        payVo.setOut_trade_no(orderSn);
        List<OrderItemEntity> list = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
        //设置订单名称
        payVo.setSubject(list.get(0).getSkuName());
        //设置订单描述
        payVo.setBody(list.get(0).getSkuAttrsVals());

        return payVo;
    }

    @Override
    public PageUtils queryPageWhithItem(Map<String, Object> params) {
        MemberRespVo memberRespVo = LoingUserInterceptor.loingUser.get();
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id",memberRespVo.getId()).orderByDesc("id")
        );
        List<OrderEntity> orders = page.getRecords().stream().map(orderEntity -> {
            List<OrderItemEntity> list = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderEntity.getOrderSn()));
            orderEntity.setOrderItems(list);
            return orderEntity;

        }).collect(Collectors.toList());

        page.setRecords(orders);
        return new PageUtils(page);
    }

    @Override
    public String handlePayResult(PayAsyncVo payAsyncVo) {
        //1.保存交易流水数据
        PaymentInfoEntity paymentInfoEntity = new PaymentInfoEntity();
        paymentInfoEntity.setAlipayTradeNo(payAsyncVo.getTrade_no());//支付宝交易流水
        paymentInfoEntity.setOrderSn(payAsyncVo.getOut_trade_no());//订单号
        paymentInfoEntity.setPaymentStatus(payAsyncVo.getTrade_status());//支付状态
        paymentInfoEntity.setCallbackTime(payAsyncVo.getNotify_time());//回调时间
        paymentInfoEntity.setCreateTime(payAsyncVo.getGmt_create());//创建时间
        paymentInfoEntity.setSubject(payAsyncVo.getSubject());//交易内容
        paymentInfoEntity.setTotalAmount(new BigDecimal(payAsyncVo.getTotal_amount()));//交易金额
        paymentInfoService.save(paymentInfoEntity);

        //2.修改订单状态
        if(payAsyncVo.getTrade_status().equals("TRADE_FINISHED")||payAsyncVo.getTrade_status().equals("TRADE_SUCCESS")){
            baseMapper.updateOrderStatus(payAsyncVo.getOut_trade_no(),OrderStatusEnum.PAYED.getCode());
        }
        return "success";
    }

    @Override
    public void saveSeckillOrder(SeckillOrderTo seckillOrderTo) {
        //1.保存订单详细信息
        OrderEntity entity = new OrderEntity();
        entity.setCreateTime(new Date());
        entity.setOrderSn(seckillOrderTo.getOrderSn());
        entity.setMemberId(seckillOrderTo.getMemberId());
        entity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        entity.setPayAmount(seckillOrderTo.getSeckillPrice().multiply(new BigDecimal(""+seckillOrderTo.getNum())));
        //2.保存订单项信息
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setRealAmount(seckillOrderTo.getSeckillPrice().multiply(new BigDecimal(""+seckillOrderTo.getNum())));
        orderItemEntity.setOrderSn(seckillOrderTo.getOrderSn());
        orderItemEntity.setSkuQuantity(seckillOrderTo.getNum());
        //TODO 远程查询商品sku信息
        //TODO 远程查询会员收货地址相关信息
        this.save(entity);
        orderItemService.save(orderItemEntity);
    }


    //保存订单以及订单项
    private void saveOrder(OrderCreateTo order) {
        //1.保存订单
        OrderEntity order1 = order.getOrder();
        order1.setModifyTime(new Date());//修改时间
        this.save(order1);
        //2.保存订单项数据
        List<OrderItemEntity> orderItems = order.getOrderItems();
        orderItemService.saveBatch(orderItems);
    }

    private OrderCreateTo    createOrder(){
        OrderCreateTo orderCreateTo = new OrderCreateTo();

        //1.创建订单
        String orderSn = IdWorker.getTimeId();
         OrderEntity order= bulidOrder(orderSn);
        orderCreateTo.setOrder(order);
        //2.创建订单项信息
        List<OrderItemEntity> orderItems= buildOrderItems(orderSn);
        orderCreateTo.setOrderItems(orderItems);
        //3. 计算价格 积分信息
        computeAmount(order,orderItems);
        return orderCreateTo;
    }

    private void computeAmount(OrderEntity order, List<OrderItemEntity> orderItems) {

        //获取订单总额
        BigDecimal totalAmount = new BigDecimal("0");
        //促销优惠总额
        BigDecimal promotionAmount = new BigDecimal("0");
        //积分优惠总额
        BigDecimal integrationAmount = new BigDecimal("0");
        //优惠卷优惠总额
        BigDecimal couponAmount = new BigDecimal("0");
        //获取成长积分
        Integer giftGrowth = 0;
        //获取的总积分
        Integer giftIntegration = 0;

        for (OrderItemEntity orderItem : orderItems) {

            totalAmount=totalAmount.add(orderItem.getRealAmount());
            promotionAmount = promotionAmount.add(orderItem.getPromotionAmount());
            integrationAmount =integrationAmount.add(orderItem.getIntegrationAmount());
            couponAmount =couponAmount.add(orderItem.getCouponAmount());
            giftGrowth =giftGrowth+ orderItem.getGiftGrowth();
            giftIntegration =giftIntegration+ orderItem.getGiftIntegration();
        }
        order.setTotalAmount(totalAmount);
        order.setPayAmount(totalAmount.add(order.getFreightAmount()));
        order.setPromotionAmount(promotionAmount);
        order.setIntegrationAmount(integrationAmount);
        order.setCouponAmount(couponAmount);
        order.setGrowth(giftGrowth);
        order.setIntegration(giftIntegration);
    }

    private List<OrderItemEntity> buildOrderItems(String orderSn) {
        //最后一次确定购物项的价格
        List<OrderItemVo> checkedItem = cartFeignService.getCheckedItem();

        if(checkedItem!=null&&checkedItem.size()>0){
            List<OrderItemEntity> collect = checkedItem.stream().map(orderItemVo -> {
                OrderItemEntity orderItemEntity = buildOrderItem(orderItemVo);
                orderItemEntity.setOrderSn(orderSn);
                return orderItemEntity;
            }).collect(Collectors.toList());
            return collect;
        }
        return null;
    }

    private OrderItemEntity buildOrderItem(OrderItemVo orderItemVo) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        //1.订单相关信息 订单号 订单id 这些 之前构建订单时已经设置了
        //2. 商品spu信息
        R r = productFeignService.getSpuInfoBySkuId(orderItemVo.getSkuId());
        SpuInfoVo spuInfoVo = r.getData(new TypeReference<SpuInfoVo>() {
        });
        orderItemEntity.setSpuId(spuInfoVo.getId());
        orderItemEntity.setSpuBrand(spuInfoVo.getBrandId().toString());
        orderItemEntity.setSpuName(spuInfoVo.getSpuName());
        orderItemEntity.setCategoryId(spuInfoVo.getCatalogId());
        //3.商品sku 信息
        orderItemEntity.setSkuId(orderItemVo.getSkuId());
        orderItemEntity.setSkuName(orderItemVo.getTitle());
        orderItemEntity.setSkuPic(orderItemVo.getImage());
        orderItemEntity.setSkuPrice(orderItemVo.getPrice());
        orderItemEntity.setSkuQuantity(orderItemVo.getCount());
        orderItemEntity.setSkuAttrsVals(StringUtils.collectionToDelimitedString(orderItemVo.getSkuAttr(),";"));
        //4.积分信息
        orderItemEntity.setGiftGrowth(orderItemVo.getPrice().intValue());
        orderItemEntity.setGiftIntegration(orderItemVo.getPrice().intValue());
        //5.价格信息
        orderItemEntity.setPromotionAmount(new BigDecimal(0));
        orderItemEntity.setCouponAmount(new BigDecimal(0));
        orderItemEntity.setIntegrationAmount(new BigDecimal(0));
        //获取原始价格
        BigDecimal originPrice = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));
        //获取真实价格
        BigDecimal realPrice = originPrice.subtract(orderItemEntity.getPromotionAmount()).subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount());
        orderItemEntity.setRealAmount(realPrice);
        //6.商品优惠信息

        return  orderItemEntity;
    }

    private OrderEntity bulidOrder(String orderSn) {
        OrderEntity orderEntity = new OrderEntity();
        OrderSubmitVo orderSubmitVo = orderSubmitVoThreadLocal.get();
        //1.设置下单订单号 下单时间
        orderEntity.setOrderSn(orderSn);
        orderEntity.setCreateTime(new Date());
        //2.设置收货信息
        R fare = wareFeignService.getFare(orderSubmitVo.getAddrId());
        FareVo fareVo = fare.getData(new TypeReference<FareVo>() {
        });
        //设置运费信息
        orderEntity.setFreightAmount(fareVo.getFare());
        //设置收货人信息
        orderEntity.setReceiverProvince(fareVo.getAddress().getProvince());
        orderEntity.setReceiverCity(fareVo.getAddress().getCity());
        orderEntity.setReceiverDetailAddress(fareVo.getAddress().getDetailAddress());
        orderEntity.setReceiverName(fareVo.getAddress().getName());
        orderEntity.setReceiverPhone(fareVo.getAddress().getPhone());
        orderEntity.setReceiverPostCode(fareVo.getAddress().getPostCode());
        orderEntity.setReceiverRegion(fareVo.getAddress().getRegion());

        //设置订单状态信息
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        orderEntity.setAutoConfirmDay(7);
        orderEntity.setDeleteStatus(0);
        //设置会员信息
        MemberRespVo memberRespVo = LoingUserInterceptor.loingUser.get();
        orderEntity.setMemberId(memberRespVo.getId());
        return orderEntity;
    }
}